package com.snail.mobile.sim.oss.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;

import org.apache.struts.upload.FormFile;
import org.dom4j.Document;
import org.dom4j.io.SAXReader;


/**
 * 文件操作工具类
 * 
 * @author Sun Xiaochen
 * @since 2008-2-1
 */

public class FileTools {

	// 限制实例化
	private FileTools() {}

	/**
	 * 从文件中读取文件
	 * 
	 * @param path
	 *            文件路径
	 * @return 文件的字符串
	 * @throws IOException
	 *             IO抛出异常
	 */
	public static String read(String path) throws IOException {
		String[] lines = readLines(path);
		StringBuilder builder = new StringBuilder();
		for (String line : lines) {
			builder.append(line);
		}
		return builder.toString();
	}

	/**
	 * 将字符串以UTF-8编码格式写入文件
	 * 
	 * @param path
	 *            文件路径
	 * @param content
	 *            写入的字符串
	 * @throws IOException
	 *             文件路径错误
	 */
	public static void write(String path, String content) throws IOException {
		Writer out = null;
		try {
			File file = new File(path);
			File parent = file.getParentFile();
			if (!parent.exists()) {
				parent.mkdirs();
			}
			out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
			out.write(content);

		} catch (Exception e) {
			//Log.error(FileUtils.class, e, "File write error, path:" + path);
		} finally {
			if (out != null) {
				out.close();
			}
		}
	}

	/**
	 * 从文本文件中读取所有的行(UTF-8编码)。
	 * 
	 * @param path
	 *            文件路径
	 * @return 以数组形式存储的所有行
	 * @throws java.io.IOException
	 *             读取文件有误时抛出
	 */
	public static String[] readLines(String path) throws IOException {
		List<String> lines = new ArrayList<String>();
		String line;
		File file = new File(path);
		if (file.exists()) {
			InputStreamReader read = new InputStreamReader(new FileInputStream(file), "UTF-8");
			BufferedReader br = new BufferedReader(read);
			line = br.readLine();
			while (line != null) {
				lines.add(line);
				line = br.readLine();
			}
			br.close();
		}

		return lines.toArray(new String[lines.size()]);
	}

	/**
	 * 将字符串数组按行写入文件，如果文件已经存在将被覆盖。
	 * 
	 * @param path
	 *            文件路径
	 * @param lines
	 *            需要写入的数据
	 * @throws java.io.IOException
	 *             写入文件有误时抛出
	 */
	public static void writeLines(String path, String[] lines) throws IOException {
		BufferedWriter bw = new BufferedWriter(new FileWriter(path));
		for (String line : lines) {
			bw.write(line);
			bw.newLine();
		}
		bw.close();
	}

	/**
	 * 打开文件并得到BufferedReader。
	 * 
	 * @param file
	 *            文件
	 * @return BufferedReader 如果文件不存在，返回null
	 * @throws java.io.IOException
	 *             读取文件有误时抛出
	 */
	public static BufferedReader getReader(File file) throws IOException {
		if (isFile(file)) {
			return new BufferedReader(new FileReader(file));
		}
		return null;
	}

	/**
	 * 打开文件，如果文件不存在，自动创建，并得到BufferedWriter。
	 * 
	 * @param file
	 *            文件
	 * @param allowOverwrite
	 *            是否运行覆盖旧文件
	 * @return BufferedWriter，如果文件存在但不运行覆盖，返回null
	 * @throws java.io.IOException
	 *             读取或创建新文件有误时抛出
	 */
	public static BufferedWriter getWriter(File file, boolean allowOverwrite) throws IOException {
		if (checkFile(file, allowOverwrite)) {
			return new BufferedWriter(new FileWriter(file));
		}

		return null;
	}

	/**
	 * 打开文件并得到InputStrea
	 * 
	 * @param file
	 *            文件
	 * @return FileInputStream，如果文件不存在，返回null
	 * @throws java.io.IOException
	 *             读取文件有误时抛出
	 */
	public static FileInputStream getInputStream(File file) throws IOException {
		if (isFile(file)) {
			return new FileInputStream(file);
		}

		return null;
	}

	/**
	 * 打开文件，如果文件不存在，自动创建，并得到FileOutputStream。
	 * 
	 * @param file
	 *            文件
	 * @param allowOverwrite
	 *            是否运行覆盖旧文件
	 * @return FileOutputStream，如果文件存在但不允许覆盖，返回null
	 * @throws java.io.IOException
	 *             读取或创建新文件有误时抛出
	 */
	public static FileOutputStream getOutputStream(File file, boolean allowOverwrite) throws IOException {
		if (checkFile(file, allowOverwrite)) {
			return new FileOutputStream(file);
		}

		return null;
	}

	/**
	 * 关闭输入流
	 * 
	 * @param inputStream
	 *            文件输入流
	 */
	public static void close(FileInputStream inputStream) {
		if (inputStream != null) {
			try {
				inputStream.close();
			} catch (IOException e) {
				//Log.error(FileUtils.class, e, "method : close@@close FileInputStream fail!");
			}
		}
	}

	/**
	 * 关闭输出流
	 * 
	 * @param outputStream
	 *            文件输出流
	 */
	public static void close(FileOutputStream outputStream) {
		if (outputStream != null) {
			try {
				outputStream.close();
			} catch (IOException e) {
				//Log.error(FileUtils.class, e, "method : close@@close FileOutputStream fail!");
			}
		}
	}

	/**
	 * 关闭BufferedReader
	 * 
	 * @param br
	 *            BufferedReader
	 */
	public static void close(BufferedReader br) {
		if (br != null) {
			try {
				br.close();
			} catch (IOException e) {
				//Log.error(FileUtils.class, e, "method : close@@close BufferedReader fail!");
			}
		}
	}

	/**
	 * 关闭BufferedWriter
	 * 
	 * @param bw
	 *            BufferedWriter
	 */
	public static void close(BufferedWriter bw) {
		if (bw != null) {
			try {
				bw.close();
			} catch (IOException e) {
				//Log.error(FileUtils.class, e, "method : close@@close BufferedWriter fail!");
			}
		}
	}

	/**
	 * 如果文件存在删除文件
	 * 
	 * @param paht
	 *            文件路径
	 */
	public static void delete(String paht) {
		File file = new File(paht);
		if (file.isFile()) {
			file.delete();
		}
	}

	/**
	 * 移动文件
	 * 
	 * @param file
	 *            文件
	 * @param destPath
	 *            目的文件夹
	 */
	public static void moveFile(File file, String destPath) {
		if (isFile(file) && destPath != null) {
			try {
				File destDir = new File(destPath);
				if (!destDir.exists()) {
					destDir.mkdir();
				}

				FileInputStream in = new FileInputStream(file);
				FileOutputStream out = new FileOutputStream(destDir.getPath() + File.separator + file.getName());

				// 传输字节
				byte[] buf = new byte[1024];
				int len;
				while ((len = in.read(buf)) > 0) {
					out.write(buf, 0, len);
				}
				in.close();
				out.close();

				file.delete();
			} catch (IOException e) {
				//Log.error(FileUtils.class, e, "method : moveFile@@can't move {} to {}!");
			}
		}
	}

	/**
	 * 批量重命名文件夹下的文件，包括文件夹
	 * 
	 * @param dir
	 *            目录
	 * @param prefix
	 *            重命名的后文件的前缀
	 * @param find
	 *            查找
	 * @param replace
	 *            替换为
	 * @param suffix
	 *            重命名后文件的后缀
	 * @return 被重命名过的文件
	 */
	public static File[] batchRename(File dir, String prefix, String find, String replace, String suffix) {
		List<File> ls = new ArrayList<File>();
		if (isDirectory(dir)) {
			File[] files = dir.listFiles();
			for (File file : files) {
				String oldName = file.getName();
				String newName = prefix + oldName.replaceAll(find, replace) + suffix;
				if (!newName.equals(oldName)) {
					File dest = new File(file.getParent() + File.separator + newName);
					if (file.renameTo(dest)) {
						ls.add(dest);
					}
				}
			}
		}
		return ls.toArray(new File[ls.size()]);
	}

	/**
	 * 批量删除一个目录下的所有文件，包括文件夹
	 * 
	 * @param dir
	 *            目录
	 */
	public static void batchDelete(File dir) {
		if (isDirectory(dir)) {
			File[] files = dir.listFiles();
			for (File file : files) {
				if (file.isDirectory()) {
					batchDelete(file);
				}
				file.delete();
			}
		}
	}

	/**
	 * 复制单个文件
	 * 
	 * @param oldPathFile
	 *            准备复制的文件源
	 * @param newPathFile
	 *            拷贝到新绝对路径带文件名
	 */
	public static void copyFile(String oldPathFile, String newPathFile) {
		try {
			int byteread = 0;
			File oldfile = new File(oldPathFile);
			if (oldfile.exists()) { // 文件存在时
				InputStream inStream = new FileInputStream(oldPathFile); // 读入原文件
				FileOutputStream fs = new FileOutputStream(newPathFile);
				byte[] buffer = new byte[1024];
				while ((byteread = inStream.read(buffer)) != -1) {
					fs.write(buffer, 0, byteread);
				}
				fs.flush();
				fs.close();
				inStream.close();
			}
		} catch (Exception e) {
			//Log.error(FileUtils.class, e, "method : copyFile@@Copy file from {} to {} failed...");
		}
	}

	/**
	 * 复制整个文件夹的内容
	 * 
	 * @param oldPath
	 *            准备拷贝的目录
	 * @param newPath
	 *            指定绝对路径的新目录
	 * @param moveSubFolder
	 *            是否需要移动子文件夹
	 */
	public static void copyFolder(String oldPath, String newPath, boolean moveSubFolder) {

		try {
			new File(newPath).mkdirs(); // 如果文件夹不存在 则建立新文件夹
			File a = new File(oldPath);
			String[] file = a.list();
			File temp = null;
			for (String aFile : file) {
				if (oldPath.endsWith(File.separator)) {
					temp = new File(oldPath + aFile);
				} else {
					temp = new File(oldPath + File.separator + aFile);
				}
				if (temp.isFile()) {
					FileInputStream input = new FileInputStream(temp);
					FileOutputStream output = new FileOutputStream(newPath + "/" + (temp.getName()));
					byte[] b = new byte[1024];
					int len;
					while ((len = input.read(b)) != -1) {
						output.write(b, 0, len);
					}
					output.flush();
					output.close();
					input.close();
				}
				if (temp.isDirectory() && moveSubFolder) {// 如果是子文件夹并且允许移动
					copyFolder(oldPath + "/" + aFile, newPath + "/" + aFile);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
			//Log.error(FileUtils.class, e, "method : copyFile@@Copy folder from {} to {} failed...");
		}
	}

	/**
	 * 复制整个文件夹的内容(不移动子文件夹)
	 * 
	 * @param oldPath
	 *            准备拷贝的目录
	 * @param newPath
	 *            指定绝对路径的新目录
	 */
	public static void copyFolder(String oldPath, String newPath) {
		copyFolder(oldPath, newPath, false);
	}

	// 检查文件是否存在，如果不存在自动创建。 如果文件存在而且不允许覆盖 -> false
	private static boolean checkFile(File file, boolean allowOverwrite) throws IOException {
		if (file != null) {
			// 检查父目录，不存在时自动创建
			File parent = file.getParentFile();
			boolean parentExist = true;
			if (parent != null && !parent.exists()) {
				parentExist = parent.mkdirs();
			}
			if (parentExist && (file.createNewFile() || (file.exists() && allowOverwrite))) {
				return true;
			}
		}
		return false;
	}

	// 是否是一个存在的文件
	public static boolean isFile(File file) {
		return file != null && file.exists() && file.isFile();
	}

	// 是否是一个存在的文件夹
	private static boolean isDirectory(File dir) {
		return dir != null && dir.exists() && dir.isDirectory();
	}

	/**
	 * 把指定路径的XML文件转换至XML文档
	 * 
	 * @param filePath
	 *            文件路径
	 * @return
	 */
	public static Document file2Document(String filePath) {
		Document doc = null;
		FileInputStream fis = null;
		try {
			SAXReader saxReader = new SAXReader();
			saxReader.setEncoding("UTF-8");
			File f = new File(filePath);
			if (!f.exists()) {
				return null;
			} else {
				fis = new FileInputStream(f);
				doc = saxReader.read(fis);
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			try {
				if (fis != null) fis.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return doc;
	}

	/**
	 * 获取文件的大小
	 * 
	 * @param filePath
	 *            文件路径
	 * @return 文件大小
	 */
	public static Long fileLength(String filePath) {
		File file = new File(filePath);
		return file.length();
	}

	/**
	 * 删除目录（文件夹）以及目录下的文件
	 * 
	 * @param sPath
	 *            被删除目录的文件路径
	 * @return 目录删除成功返回true，否则返回false
	 */
	public static boolean deleteDirectory(String sPath) {
		boolean flag;
		// 如果sPath不以文件分隔符结尾，自动添加文件分隔符
		if (!sPath.endsWith(File.separator)) {
			sPath = sPath + File.separator;
		}
		File dirFile = new File(sPath);
		// 如果dir对应的文件不存在，或者不是一个目录，则退出
		if (!dirFile.exists() || !dirFile.isDirectory()) {
			return false;
		}
		// 删除文件夹下的所有文件(包括子目录)
		File[] files = dirFile.listFiles();
		for (int i = 0; i < files.length; i++) {
			// 删除子文件
			if (files[i].isFile()) {
				delete(files[i].getAbsolutePath());
			} // 删除子目录
			else {
				flag = deleteDirectory(files[i].getAbsolutePath());
				if (!flag) break;
			}
		}
		// 删除当前目录
		if (dirFile.delete()) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 得到文件MD5 用于校验文件完整性
	 * 
	 * @param filePath
	 *            文件路径
	 * @return MD5
	 */
	public static String getMd5(String filePath) {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			FileInputStream fis = new FileInputStream(new File(filePath));
			byte[] buffer = new byte[1024 * 1024];
			int length = -1;
			if (md == null || fis == null) {
				return null;
			}
			while ((length = fis.read(buffer)) != -1) {
				md.update(buffer, 0, length);
			}
			if (fis != null) {
				fis.close();
			}
			byte[] bytes = md.digest();

			if (bytes == null) {
				return null;
			}
			StringBuffer buf = new StringBuffer();
			for (int i = 0; i < bytes.length; i++) {
				String md5s = Integer.toHexString(bytes[i] & 0xff);
				if (md5s == null || buf == null) {
					return null;
				}
				if (md5s.length() == 1) {
					buf.append("0");
				}
				buf.append(md5s);
			}

			return buf.toString();

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 拷贝文件到相应目录，回调函数用于其它处理操作，例如：删除源文件，返回新文件路径
	 * 
	 * @param targetDir
	 * @param sourceFile
	 * @param newName
	 * @return newPath
	 */
	public static String copyFileToDir(String targetDir, String sourceFile) {
		//FileUtil.copyFileToDir(targetDir, sourceFile);
		String newPath = targetDir + File.separatorChar + new File(sourceFile).getName();

		return newPath;
	}
	
	
	/**
	 * 拷贝文件到相应目录，回调函数用于其它处理操作，例如：删除源文件，返回新文件路径
	 * 
	 * @param targetDir
	 * @param sourceFile
	 * @param newName
	 * @return newPath
	 * @throws IOException 
	 */
	public static String copyFileToDir(String targetDir, FormFile sourceFile) throws IOException {
		String fileMD5 = "";

		InputStream is = null;
		FileOutputStream fos = null;
		FileInputStream md5In = null;

		try {

			File fileDir = new File(targetDir);
			if (!fileDir.exists()) {
				fileDir.mkdirs();
			}
			String filename = sourceFile.getFileName();
			is = sourceFile.getInputStream();

			// 如果服务器已经存在和上传文件同名的文件，则覆盖
			File tempFile = new File(targetDir + filename);
			if (tempFile.exists()) {
				tempFile.delete();

			}
			// 开始保存文件到服务器
			if (!filename.equals("")) {

				fos = new FileOutputStream(targetDir + filename);
				byte[] buffer = new byte[8192]; // 每次读8K字节
				int count = 0;
				// 开始读取上传文件的字节，并将其输出到服务端的上传文件输出流中
				while ((count = is.read(buffer)) > 0) {
					fos.write(buffer, 0, count); // 向服务端文件写入字节流
				}
				md5In = new FileInputStream(targetDir + filename);
				fileMD5 = getMd5(md5In);
			}
		} finally {
			if (is != null)
				is.close();
			if (fos != null)
				fos.close();
			if (md5In != null)
				md5In.close();
		}

		return fileMD5;
	}
	
	
	/**
	 * 得到文件MD5 用于校验文件完整性
	 * 
	 * @param filePath
	 *            文件路径
	 * @return MD5
	 */
	public static String getMd5(InputStream in) {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			byte[] buffer = new byte[1024 * 1024];
			int length = -1;
			if (md == null || in == null) {
				return null;
			}
			while ((length = in.read(buffer)) != -1) {
				md.update(buffer, 0, length);
			}
			byte[] bytes = md.digest();

			if (bytes == null) {
				return null;
			}
			StringBuffer buf = new StringBuffer();
			for (int i = 0; i < bytes.length; i++) {
				String md5s = Integer.toHexString(bytes[i] & 0xff);
				if (md5s == null || buf == null) {
					return null;
				}
				if (md5s.length() == 1) {
					buf.append("0");
				}
				buf.append(md5s);
			}

			return buf.toString();

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	 
}